/**
 * 创建两个子线程，一个是存钱（随机100-1000）, 一个取钱（随机100-1000）, 
 * 两个线程操作次数5次
 * 
 需求： 存先执行，取后执行，再执行存，....  
 解决方案：   同步
   1）定义两个互斥锁
   2) 将取锁在主线程先加锁，在存任务中对取锁进行解锁
   3) 在取任务中，完成后对存锁进行解锁
   ...
*/

#include <stdio.h>
#include <sys/types.h>
#include <pthread.h>

#include <string.h>
#include <time.h>
#include <stdlib.h>
#include <unistd.h>

#include <signal.h>

typedef struct {
   pthread_t tid;
   pthread_mutex_t exitlock;
} TLock;

// 定义共享数据
int balance = 0; // 余额

// 定义互斥锁
pthread_mutex_t m1lock, m2lock; 

TLock tlocks[5];

void myhandler(int signum){
    pthread_mutex_unlock(&m1lock);
    pthread_mutex_unlock(&m2lock);

    // signal(SIGINT, SIG_DFL);
}

void showCurrentTime(){
    // 显示当前时间
    // 1. 获取当前时间戳（当前时间与1900时间秒的差值）
    time_t t1 = time(NULL);
    // 2. 获取本地时间
    struct tm *current_tm= localtime(&t1);
    
    printf(
        "%d-%02d-%02d %02d:%02d:%02d ->",
        current_tm->tm_year + 1900,
        current_tm->tm_mon + 1,
        current_tm->tm_mday, 
        current_tm->tm_hour,
        current_tm->tm_min,
        current_tm->tm_sec
    );
}

void clean_task(void *arg){
    for(int i=0;i<5;i++){
        if(tlocks[i].tid == pthread_self()){
            pthread_mutex_unlock(&tlocks[i].exitlock);
            break;
        }
    }
}

void *add_task(void *arg){  // 存款任务
    int num = 0;
    pthread_cleanup_push(clean_task, NULL);
    for(int i=0;i<5;i++){
        // 申请加锁
        pthread_mutex_lock(&m1lock);
        // 以下的操作的上下文是线程安全的，没有其它线程同时执行或修改共享资源
        num = rand() % 901 + 100;
        balance += num;
        showCurrentTime();
        printf("--存储 %d, 余额： %d--\n", num, balance);

        // 解锁: 取款
        pthread_mutex_unlock(&m1lock);
        usleep(100);
    }
    pthread_cleanup_pop(1);
    return NULL;
}

void *sub_task(void *arg){  // 取款任务
    pthread_cleanup_push(clean_task, NULL);
    int num = 0;
    for(int i=0;i<5;i++){
        pthread_mutex_lock(&m1lock);

        num = rand() % 901 + 100;
        showCurrentTime();
        if(balance >= num){
            balance -= num;
            printf("--取款 %d, 余额： %d--\n", num, balance);
        }else{
            printf("--取款 %d 失败, 余额不足： %d--\n", num, balance);
        }
        pthread_mutex_unlock(&m1lock);
        usleep(100);
    }
    pthread_cleanup_pop(1);
    return NULL;
}

int main(int argc, char const *argv[])
{
    signal(SIGINT, myhandler);

    // 设置随机种子
    srand(time(NULL));

    // 初始化互斥锁 m1lock 存锁， m2lock 取锁
    pthread_mutex_init(&m1lock, NULL);
    pthread_mutex_init(&m2lock, NULL);

    // 先给m2lock上锁
    pthread_mutex_lock(&m2lock);

    pthread_t tids[5];
    for(int i=0;i<5; i++){
        if(i<3){
            pthread_create(&tids[i], NULL, add_task, NULL);
        }else{
            pthread_create(&tids[i], NULL, sub_task, NULL);
        }

        tlocks[i].tid = tids[i];
        pthread_mutex_init(&tlocks[i].exitlock, NULL);
        pthread_mutex_lock(&tlocks[i].exitlock);
    }

    for(int i=0;i<5;i++){
         pthread_detach(tids[i]);
    }
   
    
   for(int i=0;i<5;i++){
        pthread_mutex_lock(&tlocks[i].exitlock);
    }

    printf("----存款余额: %d---\n", balance);

    // 销毁锁
    pthread_mutex_destroy(&m1lock);
    pthread_mutex_destroy(&m2lock);

    return 0;
}


